Skip to content

feat: well_manager + well estimator#3972

Open
tjb-ltk wants to merge 143 commits into
developfrom
feature/byer3/wm_we
Open

feat: well_manager + well estimator#3972
tjb-ltk wants to merge 143 commits into
developfrom
feature/byer3/wm_we

Conversation

@tjb-ltk

@tjb-ltk tjb-ltk commented Feb 13, 2026

Copy link
Copy Markdown
Contributor

Replaces PR #3735 and extends PR #3971

Overview

This PR introduces

  1. An improved well schema layout and code refactor better suited for well modeling. The previous implementation primarily targeted Jacobian generation requirements for the coupled reservoir and well system.

  2. The well estimator is used to select the active well constraint by solving the well system assuming fixed reservoir conditions and selecting the constraint with the highest or lowest well flowing pressure.

    • the estimator is applied at beginning of Jacobian assembly of the coupled system
    • frequency determined via input setting
    • estimator is a data member of WellControl and a tailed version of PhysicsSolver for wells
    • logic underpins future capability to replace the segmented well model with other formulations

This is a breaking change, detailed migration instructions and migration script are posted at #4081

tjb-ltk and others added 30 commits September 29, 2025 16:50
…aint class hierachy , 3) Remove all old constraint handling methods/variables, 4) it compiles ...
…t compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_benchmark.xml
…d convert compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_benchmark.xml"

This reverts commit fa61ab1.
…well initialization vagaries assoiated with useSurfaceConditions=0
// set the reference well element where the BHP control is applied
wellControls.setReferenceGravityCoef( refElev * gravVector[2] );
wellControls.setReferenceGravityCoef( refElev * gravVector[2] ); // tjb remove

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually remove?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed and setup access to bhp constraint value. The pattern could be improved but in a different PR.

Comment thread src/coreComponents/physicsSolvers/fluidFlow/wells/WellManager.cpp Outdated
Comment thread src/coreComponents/physicsSolvers/fluidFlow/wells/WellManager.cpp
Comment thread src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp
Comment thread src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp Outdated
Comment thread src/coreComponents/physicsSolvers/fluidFlow/wells/WellManager.cpp Outdated
Comment on lines +382 to +389
// 13.4) Make sure there is at least one non-BHP constraint
bool const rate_match_found = std::any_of( constraints.begin(), constraints.end(), [&bhp_type]( const auto & constraint_tuple )
{
return std::get< 1 >( constraint_tuple ) != bhp_type;
} );
GEOS_THROW_IF( !rate_match_found,
GEOS_FMT( "Missing rate constraint for {} well {}",
(isProducerWell ? "producer" : "injector"), getName() ),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if a well has phaseVolRate while defining only a total-volume rate constraint, this check would flag things are good, but i guess initialization would hit issues later.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure about the distinction between has phaseVolRate and defining a totalVolrate... its just verifying if a rate constraint is present... current code needs 1 bhp and at least 1 rate constraint ... error checking on a specific type is done in constraint object

Comment on lines +372 to +377
string const bhp_type = isProducerWell ? MinimumBHPConstraint::catalogName() : MaximumBHPConstraint::catalogName();
bool const no_match_found = std::none_of( constraints.begin(), constraints.end(), [&bhp_type]( const auto & constraint_tuple )
{
return std::get< 1 >( constraint_tuple ) == bhp_type;
} );
GEOS_THROW_IF( no_match_found,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the sole BHP or rate constraint has constraintActive=0, these existence checks still accept it, while getBHPConstraint and the rate-list helpers filter it out. Subsequent selection either dereferences null or erases an end() iterator because the current constraint is absent from the active list.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this address your comment... for all current models constraintActive = 1. The addition of this flag was needed for 2 workflows, wellheadpressure, where the simulator can impose an "internal constraint" and the underpinning of future functionality where a well can be assigned producer and injection constraints, which then come into consideration when only the well type changes, versus the need to define 2 wells with same perforation information. For either the code will need to ensure that an active pressure and rate constraint are present.

Comment thread src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp
Comment thread src/coreComponents/physicsSolvers/fluidFlow/wells/WellManager.cpp
* @param domain the physical domain object
*/
void chopNegativeDensities( DomainPartition & domain );
#if 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it be gone ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes .. gone

m_useMass( false ),
m_useTotalMassEquation( 1 ),
m_isThermal( 0 ),
m_isCompositional( true ),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should'nt it be an integer and registered for restart ? what happen if we want to restard a non-compositional well ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable is an internal flag set for initial and restart runs. I'm guessing the integratedTests would fail if it was set for restarts.

array1d< real64 > localResidualNorm, wellResidalNorm;
array1d< real64 > localResidualNormalizer;

if( isThermal() )

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sticking to conventionm shouldn't it be set by NDOF or so ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it would add the volume balance.. I will create a separate PR so any changes are associated with a specific change.

Comment on lines +609 to +612
if( wellResidalNorm[i] > localResidualNorm[i] )
{
localResidualNorm[i] = wellResidalNorm[i];
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if( wellResidalNorm[i] > localResidualNorm[i] )
{
localResidualNorm[i] = wellResidalNorm[i];
}
localResidualNorm[i] = LvArray::math::max( localResidualNorm[i], wellResidualNorm[i] );

// step 1: compute the norm in the subRegion
if( wellControls.isWellOpen( ) )
{
wellResidalNorm = wellControls.calculateLocalWellResidualNorm( time_n,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
wellResidalNorm = wellControls.calculateLocalWellResidualNorm( time_n,
wellResidualNorm = wellControls.calculateLocalWellResidualNorm( time_n,

Comment thread src/coreComponents/physicsSolvers/fluidFlow/wells/WellManager.cpp

@jhuang2601 jhuang2601 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tjb-ltk Great job!

Please update the branch with latest develop repo, which will fix the following failures for readthedoc build:

WARNING: Error, no command xref target from index:QuickStart
WARNING: Error, no command xref target from index:Tutorials
WARNING: Error, no command xref target from index:BasicExamples
WARNING: Error, no command xref target from index:AdvancedExamples
WARNING: Error, no command xref target from index:UserGuide

// setup fluid model
string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
constitutive::MultiFluidBase & fluid = subRegion.getConstitutiveModel< constitutive::MultiFluidBase >( fluidName );
std::cout << "Validating fluid model for well " << getName() << "..." << m_useMass << std::endl;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::cout << "Validating fluid model for well " << getName() << "..." << m_useMass << std::endl;

remove?

Comment on lines +766 to +769
std::cout << " Well: " << subRegion.getName() << " Est Attempt: " << dtAttempt
<< ", ConfigurationIter: " << configurationLoopIter
<< ", NewtonIter: " << newtonIter
<< ", Residual Norm: " << residualNorm << std::endl;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is inside a Newton iteration loop and will spam output every iteration.
Remove it? or guard by a log level?

#include "fileIO/Outputs/OutputBase.hpp"
#include "physicsSolvers/fluidFlow/wells/WellFields.hpp"

#include "functions/FunctionManager.hpp"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#include "functions/FunctionManager.hpp"

remove this duplicate, as it has already been added in line 37

setApplyDefaultValue( 0 ).
setInputFlag( InputFlags::OPTIONAL ).
setDescription( "Name of the BHP table when the rate is a time dependent function" );
setDescription( "Flag to esitmate well solution prior to coupled reservoir and well solve." );

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
setDescription( "Flag to esitmate well solution prior to coupled reservoir and well solve." );
setDescription( "Flag to estimate well solution prior to coupled reservoir and well solve." );

}
/// ViewKey struct for the WellControls class
viewKeysWellControls;
/// string key for the esitmate well solution flag

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// string key for the esitmate well solution flag
/// string key for the estimate well solution flag

@@ -345,8 +401,6 @@
scale="0.1"/>
</FieldSpecifications>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
</FieldSpecifications>
</FieldSpecifications>
<!-- SPHINX_TUT_DEAD_OIL_EGG_FIELD_SPECS_END -->


<!-- SPHINX_TUT_DEAD_OIL_EGG_FIELD_SPECS_END -->
<!-- SPHINX_TUT_DEAD_OIL_EGG_OUTPUTS -->
<Outputs>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<Outputs>
<!-- SPHINX_TUT_DEAD_OIL_EGG_OUTPUTS -->
<Outputs>

<Restart
name="restartOutput"/>

</Outputs>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
</Outputs>
</Outputs>
<!-- SPHINX_TUT_DEAD_OIL_EGG_OUTPUTS_END -->


<!-- SPHINX_TUT_DEAD_OIL_EGG_OUTPUTS_END -->
<!-- SPHINX_TUT_DEAD_OIL_EGG_TASKS -->
<Tasks>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<Tasks>
<!-- SPHINX_TUT_DEAD_OIL_EGG_TASKS -->
<Tasks>

objectPath="ElementRegions/wellRegion4/wellRegion4UniqueSubRegion"
fieldName="wellElementMixtureConnectionRate"/>
fieldName="wellElementConnectionRate"/>
</Tasks>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
</Tasks>
</Tasks>
<!-- SPHINX_TUT_DEAD_OIL_EGG_TASKS_END -->

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch

@jhuang2601 jhuang2601 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tjb-ltk Great job!

Please update the branch with latest develop repo, which will fix the following failures for readthedoc build:

WARNING: Error, no command xref target from index:QuickStart
WARNING: Error, no command xref target from index:Tutorials
WARNING: Error, no command xref target from index:BasicExamples
WARNING: Error, no command xref target from index:AdvancedExamples
WARNING: Error, no command xref target from index:UserGuide

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changes XML input ci: run code coverage enables running of the code coverage CI jobs ci: run CUDA builds Allows to triggers (costly) CUDA jobs ci: run integrated tests Allows to run the integrated tests in GEOS CI flag: ready for review flag: requires rebaseline Requires rebaseline branch in integratedTests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants